#include "stdafx.h"
#include "Settings.h"

#include "Exception.h"
#include "Filesystem.h"

namespace Cvekas {

SettingsGroup::SettingsGroup(const std::string& name, const std::string& filename)
: name(name), filename(filename)
{
}

void SettingsGroup::deserialize(const MMLNode& mml)
{
	if(mml.name != "group")
		throw EXCEPTION("Node must be named group");
	if(mml.value != mml.name)
		throw EXCEPTION("Node must have same value as SettingsGroup name");

	std::list<MMLNode>::const_iterator itr = mml.children.begin();
	for(; itr != mml.children.end(); ++itr)
	{
		if(!itr->children.empty())
			throw EXCEPTION("Setting can't have any children");

		settings[itr->name] = SettingValue(itr->value);
	}
}

MMLNode SettingsGroup::serialize() const
{
	MMLNode result("group", name);

	if(settings.size() == 0)
		return result;

	std::map<std::string, SettingValue>::const_iterator itr = settings.begin();
	for(; itr != settings.end(); ++itr)
	{
		MMLNode setting(itr->first, static_cast<std::string>(itr->second));
		result.append(setting);
	}

	return result;
}

SettingValue& SettingsGroup::operator[](const std::string& name)
{
	std::pair<std::map<std::string, SettingValue>::iterator, bool> result =
		settings.insert(std::make_pair(name, SettingValue()));
	
	return result.first->second;
}

Settings::Settings(const std::string &filename)
{
	load(filename);
}

void Settings::load(const std::string& filename)
{
	MML input(Filesystem::readFileToString(filename));

	MMLNode& root = input.getRoot();

	if(root.name != "settings")
		throw EXCEPTION("Root node must be named settings");

	std::list<MMLNode>::const_iterator itr = root.children.begin();
	for(; itr != root.children.end(); ++itr)
	{
		if(itr->name != "group")
			throw EXCEPTION("Node must be named group");

		std::pair<std::map<std::string, SettingsGroup>::iterator, bool> result = 
				groups.insert(std::make_pair(itr->value, SettingsGroup(itr->value, filename)));
		if(!result.second)
		{
			result.first->second.name = itr->value;
			result.first->second.filename = filename;
		}

		result.first->second.deserialize(*itr);
	}
}

void Settings::save(const std::string& group_name)
{
	SettingsGroup& group = (*this)[group_name];
	
	MML output;
	MMLNode& root = output.getRoot();

	root.name = "settings";
	root.value = "_";

	std::map<std::string, SettingsGroup>::const_iterator itr = groups.begin();
	for(; itr != groups.end(); ++itr)
	{
		if(itr->second.filename != group.filename)
			continue;

		root.append(itr->second.serialize());
	}

	Filesystem::writeStringToFile(group.filename, output.serialize());
}

void Settings::insert(const std::string& name, const SettingsGroup& group)
{
	std::pair<std::map<std::string, SettingsGroup>::iterator, bool> result =
		groups.insert(std::make_pair(name, group));

	if(!result.second)
		throw EXCEPTION("SettingsGroup " + name + " already exists");
}

SettingsGroup& Settings::operator[](const std::string& group_name)
{
	std::map<std::string, SettingsGroup>::iterator itr = groups.find(group_name);

	if(itr == groups.end())
		throw EXCEPTION("Settings group " + group_name + " doesn't exist");

	return itr->second;
}

} // namespace
	
